home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Express Pd: GALORE
/
Express Pd Galore - The Amiga PD & Shareware CD (1994)(Express Pd)[!][Amiga-CD32-CDTV].iso
/
productivity
/
term
/
termtextbuffer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-16
|
42KB
|
1,761 lines
/*
** termTextBuffer.c
**
** Support routines for the text buffer.
**
** Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
** All Rights Reserved
*/
#include "termGlobal.h"
/* Gadget ID codes. */
enum { GAD_SCROLLER,GAD_UP,GAD_DOWN };
/* Menu ID codes. */
enum { MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF_CONTENTS,MEN_QUITBUF };
/* Gadget ID codes. */
enum { GAD_STRING,GAD_LOAD,GAD_OK,GAD_CANCEL };
/* A handy macro to determine the length of a string. */
#define LINE_WIDTH(s) (s)[-1]
/* The dimensions of the scroller images. */
#define ARROW_WIDTH 18
#define ARROW_HEIGHT 11
STATIC struct NewMenu BufferMenu[] =
{
{ NM_TITLE, NULL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_SEARCH},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_REPEAT},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_GOTO},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_CLEARBUF_CONTENTS},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_QUITBUF},
{ NM_END, 0, 0 , 0, 0, (APTR)0}
};
/* Some private data (render info & window). */
STATIC struct Window *BufferWindow;
STATIC struct Screen *BufferScreen;
STATIC struct RastPort *BPort;
STATIC APTR BufferVisualInfo;
STATIC LONG NumBufferLines,
NumBufferColumns,
LastTopLine;
STATIC BYTE BufferTerminated;
STATIC WORD LocalTextFontWidth,
LocalTextFontHeight,
LocalTextFontBase;
STATIC struct TTextAttr LocalTextFont;
STATIC UBYTE LocalTextFontName[MAX_FILENAME_LENGTH];
STATIC struct TTextAttr LocalUserFont;
STATIC UBYTE LocalUserFontName[MAX_FILENAME_LENGTH];
STATIC LONG TopLine = -1,
DisplayedLines;
STATIC struct SearchInfo *BufferSearchInfo;
STATIC BYTE SearchForward = TRUE;
STATIC struct Gadget *Scroller,
*UpArrow,
*DownArrow;
STATIC struct Image *UpImage,
*DownImage;
STATIC UWORD *BufferLineWidths,
*BufferLineOffsets,
*BufferColumnOffsets;
/* DeleteScroller(VOID):
*
* Delete scroller and arrow objects.
*/
STATIC VOID
DeleteScroller(VOID)
{
if(Scroller)
{
DisposeObject(Scroller);
Scroller = NULL;
}
if(UpArrow)
{
DisposeObject(UpArrow);
UpArrow = NULL;
}
if(DownArrow)
{
DisposeObject(DownArrow);
DownArrow = NULL;
}
if(UpImage)
{
DisposeObject(UpImage);
UpImage = NULL;
}
if(DownImage)
{
DisposeObject(DownImage);
DownImage = NULL;
}
}
/* CreateScroller(LONG Height):
*
* Create scroller and arrow objects.
*/
STATIC BYTE __regargs
CreateScroller(LONG Height)
{
struct DrawInfo *DrawInfo;
BYTE Result = FALSE;
if(DrawInfo = GetScreenDrawInfo(BufferScreen))
{
if(UpImage = (struct Image *)NewObject(NULL,"sysiclass",
SYSIA_Size, SYSISIZE_MEDRES,
SYSIA_Which, UPIMAGE,
SYSIA_DrawInfo, DrawInfo,
TAG_DONE))
{
if(DownImage = (struct Image *)NewObject(NULL,"sysiclass",
SYSIA_Size, SYSISIZE_MEDRES,
SYSIA_Which, DOWNIMAGE,
SYSIA_DrawInfo, DrawInfo,
TAG_DONE))
{
LONG ScrollerHeight,LeftEdge;
ScrollerHeight = Height - 2 * ARROW_HEIGHT;
LeftEdge = BufferScreen -> Width - ARROW_WIDTH;
if(Scroller = NewObject(NULL,"propgclass",
GA_ID, GAD_SCROLLER,
GA_Top, 0,
GA_Left, LeftEdge,
GA_Width, ARROW_WIDTH,
GA_Height, ScrollerHeight,
GA_Immediate, TRUE,
GA_FollowMouse, TRUE,
GA_RelVerify, TRUE,
PGA_Freedom, FREEVERT,
PGA_NewLook, TRUE,
PGA_Visible, 1,
PGA_Total, 1,
TAG_DONE))
{
STATIC struct TagItem ArrowMappings[] = { GA_ID,GA_ID,TAG_END };
if(UpArrow = NewObject(NULL,"buttongclass",
GA_ID, GAD_UP,
GA_Image, UpImage,
GA_Left, LeftEdge,
GA_Top, ScrollerHeight,
GA_Height, ARROW_HEIGHT,
GA_Width, ARROW_WIDTH,
GA_Immediate, TRUE,
GA_RelVerify, TRUE,
GA_Previous, Scroller,
ICA_TARGET, ICTARGET_IDCMP,
ICA_MAP, ArrowMappings,
TAG_DONE))
{
if(DownArrow = NewObject(NULL,"buttongclass",
GA_ID, GAD_DOWN,
GA_Image, DownImage,
GA_Left, LeftEdge,
GA_Top, ScrollerHeight + ARROW_HEIGHT,
GA_Height, ARROW_HEIGHT,
GA_Width, ARROW_WIDTH,
GA_Immediate, TRUE,
GA_RelVerify, TRUE,
GA_Previous, UpArrow,
ICA_TARGET, ICTARGET_IDCMP,
ICA_MAP, ArrowMappings,
TAG_DONE))
Result = TRUE;
}
}
}
}
FreeScreenDrawInfo(BufferScreen,DrawInfo);
}
if(!Result)
DeleteScroller();
return(Result);
}
/* PrintLine(STRPTR Buffer,LONG LineNumber):
*
* Print a line at a given line number in the displayed area.
*/
STATIC VOID
PrintLine(STRPTR Buffer,LONG LineNumber)
{
WORD Length = Buffer[-1];
/* Print the text. */
if(Length)
{
Move(BPort,0,BufferLineOffsets[LineNumber] + LocalTextFontBase);
if(Length > NumBufferColumns)
Length = NumBufferColumns;
Text(BPort,Buffer,Length);
}
/* The line doesn't exactly fill the displayed line,
* so erase the remaining columns.
*/
if(Length < BufferLineWidths[LineNumber])
{
SetAPen(BPort,0);
RectFill(BPort,BufferColumnOffsets[Length],BufferLineOffsets[LineNumber],BufferColumnOffsets[BufferLineWidths[LineNumber]] - 1,BufferLineOffsets[LineNumber + 1] - 1);
SetAPen(BPort,1);
}
BufferLineWidths[LineNumber] = Length;
}
/* RedrawScreen(LONG FirstLine):
*
* Redraw the contents of the entire screen and return the
* number of lines actually drawn.
*/
STATIC LONG
RedrawScreen(LONG FirstLine)
{
LONG i,Last,Line = 0,Result;
ObtainSemaphore(BufferSemaphore);
/* Determine last line to display. */
if((Last = FirstLine + NumBufferLines) >= Lines)
Last = Lines;
Result = Last - FirstLine;
if(Lines)
{
if(LastTopLine != -1)
{
LONG Delta = FirstLine - LastTopLine;
if(ABS(Delta) < NumBufferLines)
{
/* No change? */
if(!Delta)
{
ReleaseSemaphore(BufferSemaphore);
return(Result);
}
else
{
LastTopLine = FirstLine;
/* Scrolled up? */
if(Delta < 0)
{
for(i = NumBufferLines - 1 ; i >= -Delta ; i--)
BufferLineWidths[i] = BufferLineWidths[i + Delta];
ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[-Delta],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines + Delta],MINTERM_COPY);
Last = FirstLine - Delta;
}
else
{
for(i = Delta ; i < NumBufferLines ; i++)
BufferLineWidths[i - Delta] = BufferLineWidths[i];
/* Scrolled down. */
ClipBlit(BPort,0,BufferLineOffsets[Delta],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Delta],MINTERM_COPY);
FirstLine += NumBufferLines - Delta;
Line = NumBufferLines - Delta;
}
}
}
else
LastTopLine = FirstLine;
}
else
LastTopLine = FirstLine;
if(BufferLines)
{
for(i = FirstLine ; i < Last ; i++)
PrintLine(BufferLines[i],Line++);
}
}
ReleaseSemaphore(BufferSemaphore);
/* We didn't fill the whole screen, so clear the rest. */
if(Result < NumBufferLines)
{
WORD i;
for(i = Result ; i < NumBufferLines ; i++)
BufferLineWidths[i] = 0;
SetAPen(BPort,0);
RectFill(BPort,0,BufferLineOffsets[Result],BufferColumnOffsets[NumBufferColumns] - 1,BufferLineOffsets[NumBufferLines] - 1);
SetAPen(BPort,1);
}
return(Result);
}
/* MarkArea(LONG Column,LONG Line,LONG Length):
*
* Mark an area in the term Buffer window.
*/
STATIC VOID
MarkArea(LONG Column,LONG Line,LONG Length)
{
STATIC LONG OldColumn = -1,OldLine = -1,OldLength = -1;
if(OldColumn != -1)
ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[OldColumn],BufferLineOffsets[OldLine],BufferColumnOffsets[OldLength],LocalTextFontHeight,MINTERM_NOT_C);
if(Column != -1)
{
if(OldColumn != Column || OldLine != Line || OldLength != Length)
ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Column],BufferLineOffsets[Line],BufferColumnOffsets[Length],LocalTextFontHeight,MINTERM_NOT_C);
}
OldColumn = Column;
OldLine = Line;
OldLength = Length;
}
/* BufferClipPage(struct BlockMarker *Marker):
*
* Send the marked area to the clipboard.
*/
STATIC VOID __inline
BufferClipPage(struct BlockMarker *Marker)
{
if(BufferLines)
{
struct IFFHandle *Handle;
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
{
InitIFFasClip(Handle);
if(!OpenIFF(Handle,IFFF_WRITE))
{
if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
{
if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
{
LONG Lines = Marker -> LastLine - Marker -> FirstLine - 1,
i;
if(LINE_WIDTH(BufferLines[Marker -> FirstLine]) > Marker -> FirstColumn)
WriteTrimmedString(Handle,&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],LINE_WIDTH(BufferLines[Marker -> FirstLine]) - Marker -> FirstColumn);
WriteChunkBytes(Handle,"\n",1);
if(Lines > 0)
{
for(i = 0 ; i < Lines ; i++)
{
if(LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]))
WriteTrimmedString(Handle,BufferLines[Marker -> FirstLine + 1 + i],LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]));
WriteChunkBytes(Handle,"\n",1);
}
}
if(Marker -> LastColumn > LINE_WIDTH(BufferLines[Marker -> LastLine]))
WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],LINE_WIDTH(BufferLines[Marker -> LastLine]));
else
WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],Marker -> LastColumn);
WriteChunkBytes(Handle,"\n",1);
PopChunk(Handle);
}
PopChunk(Handle);
}
CloseIFF(Handle);
}
CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
}
FreeIFF(Handle);
}
}
}
/* BufferClip(VOID):
*
* Start buffer marking process.
*/
STATIC VOID
BufferClip(VOID)
{
struct BlockMarker *Marker;
LONG FirstX = BufferWindow -> MouseX / LocalTextFontWidth,
FirstY = BufferWindow -> MouseY / LocalTextFontHeight;
if(Marker = BM_SetMark(BufferWindow -> RPort,ToggleSelect,ToggleSelect,NumBufferColumns,NumBufferLines,0,0,TopLine,Lines,BufferWindow -> MouseX / LocalTextFontWidth,BufferWindow -> MouseY / LocalTextFontHeight,LocalTextFontWidth,LocalTextFontHeight))
{
struct IntuiMessage *Massage;
ULONG Code,IClass;
BYTE Done = FALSE,Aborted = FALSE;
LONG PlusX = LocalTextFontWidth - 1,
MouseX,MouseY,
Delta = 0;
ReportMouse(TRUE,BufferWindow);
while(!Done)
{
WaitPort(BufferWindow -> UserPort);
while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
{
IClass = Massage -> Class;
Code = Massage -> Code;
MouseX = Massage -> MouseX;
MouseY = Massage -> MouseY;
ReplyMsg(Massage);
if(IClass == IDCMP_INACTIVEWINDOW)
{
Done = Aborted = TRUE;
break;
}
if(IClass == IDCMP_INTUITICKS && Delta != 0)
{
if(BufferLines)
{
if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
{
if(Delta < 0)
{
WORD i;
for(i = NumBufferLines - 1 ; i > -Delta ; i--)
BufferLineWidths[i] = BufferLineWidths[i + Delta];
if(DisplayedLines)
ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
BufferLineWidths[0] = NumBufferColumns;
PrintLine(BufferLines[--TopLine],0);
}
else
{
WORD i;
for(i = Delta ; i < NumBufferLines ; i++)
BufferLineWidths[i - Delta] = BufferLineWidths[i];
if(DisplayedLines)
ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
TopLine++;
}
Marker -> Top += Delta;
Marker -> LastY -= Delta;
BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
}
else
Delta = 0;
}
}
if(IClass == IDCMP_MOUSEBUTTONS && (Code & IECODE_UP_PREFIX))
{
BM_Draw(Marker,Marker -> Unselect);
Done = TRUE;
break;
}
if(IClass == IDCMP_MOUSEMOVE)
{
BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,0);
if(MouseY < 1)
{
if(TopLine > 0)
Delta = -1;
}
else
{
if(MouseY >= BufferWindow -> Height - 1 && TopLine + NumBufferLines < Lines)
Delta = 1;
}
while(Delta)
{
MouseX = Window -> MouseX;
MouseY = Window -> MouseY;
if((Delta < 0 && MouseY > 0) || (Delta > 0 && MouseY < BufferWindow -> Height - 1))
break;
else
{
if(BufferLines)
{
if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
{
if(Delta < 0)
{
WORD i;
for(i = NumBufferLines - 1 ; i > -Delta ; i--)
BufferLineWidths[i] = BufferLineWidths[i + Delta];
if(DisplayedLines)
ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
BufferLineWidths[0] = NumBufferColumns;
PrintLine(BufferLines[--TopLine],0);
}
else
{
WORD i;
for(i = Delta ; i < NumBufferLines ; i++)
BufferLineWidths[i - Delta] = BufferLineWidths[i];
if(DisplayedLines)
ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
TopLine++;
}
Marker -> Top += Delta;
Marker -> LastY -= Delta;
BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
else
break;
}
else
break;
}
}
Delta = 0;
}
}
}
ReportMouse(FALSE,BufferWindow);
while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
ReplyMsg(Massage);
if(!Aborted)
{
if(FirstX != BufferWindow -> MouseX / LocalTextFontWidth || FirstY != BufferWindow -> MouseY / LocalTextFontHeight)
{
SetWait(BufferWindow);
if(Marker -> FirstColumn == Marker -> Width)
{
Marker -> FirstLine++;
Marker -> FirstColumn = 0;
}
if(Marker -> LastColumn == 0)
{
Marker -> LastLine--;
Marker -> LastColumn = Marker -> Width;
}
if(Marker -> FirstLine <= Marker -> LastLine)
{
if(Marker -> FirstLine != Marker -> LastLine || Marker -> FirstColumn != Marker -> LastColumn)
{
if(BufferLines)
{
if(Marker -> FirstLine == Marker -> LastLine)
SaveClip(&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],Marker -> LastColumn - Marker -> FirstColumn);
else
BufferClipPage(Marker);
}
}
}
ClrWait(BufferWindow);
}
}
FreeVec(Marker);
}
}
/* StartBufferSearch(BYTE NewSearchString):
*
* Search the buffer for a string.
*/
STATIC VOID
StartBufferSearch(BYTE NewSearchString)
{
BlockWindow(BufferWindow);
if(Lines)
{
STATIC UBYTE SearchBuffer[256];
BYTE StartSearch = TRUE;
if(NewSearchString || !SearchBuffer[0])
{
if(GetSearchString(BufferWindow,&BufferTerminated,SearchBuffer,&SearchForward))
{
if(SearchBuffer[0])
{
if(BufferSearchInfo)
DeleteSearchInfo(BufferSearchInfo);
BufferSearchInfo = CreateSearchInfo(SearchBuffer,SearchForward);
}
else
StartSearch = FALSE;
}
else
StartSearch = FALSE;
}
else
{
if(!BufferSearchInfo)
BufferSearchInfo = CreateSearchInfo(SearchBuffer,TRUE);
}
if(StartSearch && BufferSearchInfo)
{
LONG LineNumber;
ObtainSemaphore(BufferSemaphore);
LineNumber = SearchTextBuffer(BufferSearchInfo);
ReleaseSemaphore(BufferSemaphore);
if(LineNumber == -1)
{
BlockWindows();
MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_DID_NOT_FIND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SearchBuffer);
ReleaseWindows();
FlushMsg(BufferWindow);
BufferSearchInfo -> FoundY = -1;
MarkArea(-1,-1,-1);
}
else
{
if(LineNumber < TopLine)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(TopLine = LineNumber);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
else
{
if(LineNumber > TopLine + DisplayedLines - 1)
{
MarkArea(-1,-1,-1);
if(LineNumber >= Lines - NumBufferLines)
{
LONG NewCurrentLine;
if((NewCurrentLine = Lines - NumBufferLines) < 0)
NewCurrentLine = 0;
if(TopLine != NewCurrentLine)
DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
}
else
DisplayedLines = RedrawScreen(TopLine = LineNumber);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
}
MarkArea(BufferSearchInfo -> FoundX,LineNumber - TopLine,BufferSearchInfo -> PatternWidth);
}
}
}
else
MyEasyRequest(BufferWindow,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
ReleaseWindow(BufferWindow);
}
/* LaunchBuffer():
*
* Launch the buffer process.
*/
BYTE
LaunchBuffer()
{
/* Is the buffer process already running? */
if(BufferProcess)
{
/* Tell it to bring its screen to the front. */
Signal(BufferProcess,SIG_TOFRONT);
/* Return success. */
return(TRUE);
}
else
{
struct MsgPort *ReplyPort;
BYTE Result = FALSE;
/* Create reply port. */
if(ReplyPort = CreateMsgPort())
{
struct Message *Message;
/* Create startup message. */
if(Message = (struct Message *)AllocVec(sizeof(struct Message),MEMF_ANY|MEMF_CLEAR))
{
Message -> mn_ReplyPort = ReplyPort;
Message -> mn_Length = sizeof(struct Message);
/* Launc the buffer process. */
if(BufferProcess = (struct Process *)CreateNewProcTags(
NP_Entry, BufferServer,
NP_Name, "term buffer process",
NP_Priority, 0,
NP_StackSize, 8192,
NP_WindowPtr, -1,
TAG_END))
{
/* Send the startup message. */
PutMsg(&BufferProcess -> pr_MsgPort,Message);
/* Wait for reply. */
WaitPort(ReplyPort);
/* Pick up the reply. */
GetMsg(ReplyPort);
/* Is the process still running? */
if(BufferProcess)
Result = TRUE;
}
/* Free the startup message. */
FreeVec(Message);
}
/* Delete the reply port. */
DeleteMsgPort(ReplyPort);
}
/* Return the result. */
return(Result);
}
}
/* TerminateBuffer():
*
* Terminate the buffer process.
*/
VOID
TerminateBuffer()
{
if(BufferProcess)
{
Forbid();
Signal(BufferProcess,SIG_KILL);
ClrSignal(SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
}
LastTopLine = -1;
}
/* BufferServer():
*
* Asynchronous task to display the data stored in the
* scrollback display buffer.
*/
VOID __saveds
BufferServer()
{
struct ColorSpec ColorSpec[3];
ULONG SignalSet;
struct IntuiMessage *Massage;
ULONG IClass,Code,Qualifier,LastQualifier = NULL;
UBYTE Char,LastChar = 0;
LONG MouseX,MouseY,LastWidth = 0;
UBYTE PercentBuffer[80];
struct Menu *BufferMenuStrip;
LONG Width;
ULONG DisplayMode;
struct Rectangle DisplayClip;
struct DimensionInfo DimensionInfo;
UWORD SomeColour,Height;
struct TextFont *LocalFont;
struct Message *StartupMessage;
struct MsgPort *StartupPort = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
struct TagItem *TagList;
/* Wait for startup message. */
WaitPort(StartupPort);
StartupMessage = GetMsg(StartupPort);
/* Clone the global font data. */
LocalTextFontWidth = TextFontWidth;
LocalTextFontHeight = TextFontHeight;
LocalTextFontBase = TextFontBase;
memcpy(&LocalTextFont,&TextAttr,sizeof(struct TTextAttr));
LocalTextFont . tta_Name = LocalTextFontName;
strcpy(LocalTextFontName,TextAttr . tta_Name);
memcpy(&LocalUserFont,&UserFont,sizeof(struct TTextAttr));
LocalUserFont . tta_Name = LocalUserFontName;
strcpy(LocalUserFontName,UserFont . tta_Name);
/* Reset top line index. */
LastTopLine = -1;
/* Up and running... */
BufferTerminated = FALSE;
/* Set up the startup colours for our buffer screen. */
ColorSpec[0] . ColorIndex = 0;
ColorSpec[0] . Red = (Config -> ScreenConfig -> Colours[0] >> 8) & 0xF;
ColorSpec[0] . Green = (Config -> ScreenConfig -> Colours[0] >> 4) & 0xF;
ColorSpec[0] . Blue = (Config -> ScreenConfig -> Colours[0] ) & 0xF;
switch(Config -> ScreenConfig -> ColourMode)
{
case COLOUR_EIGHT:
SomeColour = Config -> ScreenConfig -> Colours[7];
break;
case COLOUR_SIXTEEN:
SomeColour = Config -> ScreenConfig -> Colours[15];
break;
case COLOUR_AMIGA:
case COLOUR_MONO:
SomeColour = Config -> ScreenConfig -> Colours[1];
break;
}
ColorSpec[1] . ColorIndex = 1;
ColorSpec[1] . Red = (SomeColour >> 8) & 0xF;
ColorSpec[1] . Green = (SomeColour >> 4) & 0xF;
ColorSpec[1] . Blue = (SomeColour ) & 0xF;
ColorSpec[2] . ColorIndex = -1;
/* We'll use a fixed screen width, only the
* height is adapted from the main screen.
*/
DisplayMode = Config -> ScreenConfig -> DisplayMode;
/* Set up the actual width of the screen we want. */
Width = Config -> CaptureConfig -> BufferWidth * LocalTextFontWidth + ARROW_WIDTH + 1;
/* Get the mode dimension info. */
if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,DisplayMode))
{
/* Determine maximum text overscan width. */
LONG TextWidth = DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1;
/* Too small? */
if(Width < DimensionInfo . MinRasterWidth)
Width = DimensionInfo . MinRasterWidth;
/* Far too large? */
if(Width > DimensionInfo . MaxRasterWidth)
Width = DimensionInfo . MaxRasterWidth;
/* A bit too large? */
if(Width > TextWidth)
Width = TextWidth;
if(LocalFont = OpenFont(&LocalTextFont))
{
/* Inquire the text overscan dimensions. */
if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
{
/* Centre the buffer screen. */
if(DisplayClip . MaxX - DisplayClip . MinX + 1 > Width)
{
LONG Differ = (DisplayClip . MaxX - DisplayClip . MinX + 1 - Width) / 2;
switch(Config -> CaptureConfig -> BufferScreenPosition)
{
case SCREEN_LEFT:
DisplayClip . MaxX = DisplayClip . MinX + Width;
break;
case SCREEN_RIGHT:
DisplayClip . MinX = DisplayClip . MaxX - Width;
break;
case SCREEN_CENTRE:
DisplayClip . MinX += Differ;
DisplayClip . MaxX -= Differ;
break;
}
}
/* Open a single bitplane clone of the main screen. */
if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
SA_Title, LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),
SA_Depth, 1,
SA_DClip, &DisplayClip,
SA_DisplayID, DisplayMode,
SA_Font, &LocalUserFont,
SA_Behind, TRUE,
SA_AutoScroll, TRUE,
SA_Colors, ColorSpec,
TAG_END))
{
if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
{
LocalizeMenu(BufferMenu,MSG_TERMBUFFER_PROJECT_MEN);
if(BufferMenuStrip = CreateMenus(BufferMenu,TAG_DONE))
{
if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
GTMN_TextAttr, &LocalUserFont,
GTMN_NewLookMenus, TRUE,
TAG_DONE))
{
WORD TitleOffset,Len;
Height = (BufferScreen -> Height - (BufferScreen -> BarHeight + 2)) / LocalTextFontHeight;
Len = strlen(LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT));
TitleOffset = TextLength(BufferScreen -> BarLayer -> rp,LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),Len) + TextLength(BufferScreen -> BarLayer -> rp," ",1) + 4;
/* Open a cute window on our buffer screen. */
if(BufferWindow = OpenWindowTags(NULL,
WA_Top, BufferScreen -> BarHeight + 2,
WA_Left, 0,
WA_Width, BufferScreen -> Width,
WA_Height, Height * LocalTextFontHeight,
WA_Backdrop, TRUE,
WA_Borderless, TRUE,
WA_SmartRefresh,FALSE,
WA_CustomScreen,BufferScreen,
WA_RMBTrap, TRUE,
WA_NewLookMenus,TRUE,
WA_RptQueue, 1,
WA_IDCMP, IDCMP_IDCMPUPDATE | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE,
TAG_DONE))
{
if(BufferLineWidths = (UWORD *)AllocVec(2 * sizeof(UWORD) * (BufferWindow -> Height / LocalTextFontHeight + 1) + sizeof(UWORD) * (BufferWindow -> Width / LocalTextFontWidth + 1),MEMF_ANY | MEMF_CLEAR))
{
UWORD Index;
WORD i;
BufferLineOffsets = &BufferLineWidths[BufferWindow -> Height / LocalTextFontHeight + 1];
BufferColumnOffsets = &BufferLineOffsets[BufferWindow -> Height / LocalTextFontHeight + 1];
for(i = Index = 0 ; i < BufferWindow -> Height / LocalTextFontHeight + 1 ; i++)
{
BufferLineOffsets[i] = Index;
Index += LocalTextFontHeight;
}
for(i = Index = 0 ; i < BufferWindow -> Width / LocalTextFontWidth + 1 ; i++)
{
BufferColumnOffsets[i] = Index;
Index += LocalTextFontWidth;
}
if(CreateScroller(BufferWindow -> Height))
{
/* Signal our father process that
* we're running.
*/
ReplyMsg(StartupMessage);
StartupMessage = NULL;
SetMenuStrip(BufferWindow,BufferMenuStrip);
AddGList(BufferWindow,Scroller,(UWORD)-1,(UWORD)-1,NULL);
RefreshGList(Scroller,BufferWindow,NULL,(UWORD)-1);
/* Determine maximum dimensions of
* the buffer screen (in rows and
* columns).
*/
NumBufferColumns = (BufferWindow -> Width - (ARROW_WIDTH + 1)) / LocalTextFontWidth;
NumBufferLines = BufferWindow -> Height / LocalTextFontHeight;
if(TopLine == -1 || !Config -> CaptureConfig -> RememberBufferScreen)
{
switch(Config -> CaptureConfig -> OpenBufferScreen)
{
case BUFFER_TOP:
TopLine = 0;
break;
case BUFFER_END:
if((TopLine = Lines - NumBufferLines) < 0)
TopLine = 0;
break;
default:
TopLine = 0;
break;
}
}
if(TopLine > Lines - NumBufferLines)
TopLine = 0;
Restart: BPort = BufferWindow -> RPort;
SetFont(BPort,LocalFont);
/* Bring the screen to the front. */
BumpWindow(BufferWindow);
/* Set the drawing pens for the window. */
SetAPen(BPort,1);
SetBPen(BPort,0);
SetDrMd(BPort,JAM2);
/* Initial creation of the buffer display. */
DisplayedLines = RedrawScreen(TopLine);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top, TopLine,
PGA_Total, Lines,
PGA_Visible, NumBufferLines,
TAG_DONE);
BufferWindow -> Flags &= ~WFLG_RMBTRAP;
do
{
/* Show where we are. */
if(Lines)
{
LONG Width;
SetAPen(BufferScreen -> BarLayer -> rp,0);
SetBPen(BufferScreen -> BarLayer -> rp,1);
SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);
if(LocaleBase)
SPrintf(PercentBuffer,"%lD/%lD (%ld%%)",TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
else
SPrintf(PercentBuffer,"%ld/%ld (%ld%%)",TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
Len = strlen(PercentBuffer);
Move(BufferScreen -> BarLayer -> rp,TitleOffset,BufferScreen -> BarLayer -> rp -> Font -> tf_Baseline + 1);
Text(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
Width = TextLength(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
if(LastWidth > Width)
{
SetAPen(BufferScreen -> BarLayer -> rp,1);
RectFill(BufferScreen -> BarLayer -> rp,TitleOffset + Width,1,TitleOffset + LastWidth - 1,BufferScreen -> BarLayer -> rp -> Font -> tf_YSize);
}
LastWidth = Width;
}
SignalSet = Wait(SIG_KILL | SIG_TOFRONT | SIG_UPDATE | SIG_MOVEUP | PORTMASK(BufferWindow -> UserPort));
/* Leave the town? */
if(SignalSet & SIG_KILL)
BufferTerminated = TRUE;
/* Bring our window to the front. */
if(SignalSet & SIG_TOFRONT)
BumpWindow(BufferWindow);
/* We've got one more line in the
* buffer.
*/
if(SignalSet & SIG_UPDATE)
{
if(BufferLines && Lines)
{
if(Lines - TopLine > DisplayedLines && DisplayedLines < NumBufferLines)
{
LONG i = TopLine + DisplayedLines;
do
PrintLine(BufferLines[i++],DisplayedLines++);
while(DisplayedLines < NumBufferLines && i < Lines);
}
}
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Total, Lines,
PGA_Visible, DisplayedLines,
TAG_DONE);
Signal(ThisProcess,SIG_HANDSHAKE);
}
/* The contents of the buffer have moved
* up a line.
*/
if(SignalSet & SIG_MOVEUP)
{
if(TopLine > 0)
{
LastTopLine = --TopLine;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
else
{
LONG i;
MarkArea(-1,-1,-1);
for(i = 0 ; i < NumBufferLines - 1 ; i++)
BufferLineWidths[i] = BufferLineWidths[i + 1];
ClipBlit(BPort,0,BufferLineOffsets[1],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
PrintLine(BufferLines[NumBufferLines - 1],NumBufferLines - 1);
}
Signal(ThisProcess,SIG_HANDSHAKE);
}
/* Process the incoming window
* input.
*/
while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
{
IClass = Massage -> Class;
Code = Massage -> Code;
Qualifier = Massage -> Qualifier;
MouseX = Massage -> MouseX;
MouseY = Massage -> MouseY;
TagList = (struct TagItem *)Massage -> IAddress;
/* This hack is necessary to obtain the
* character codes generated for the cursor
* keys. A control or alternate qualifier
* would spoil the result (i.e. we would
* not get a valid key code).
*/
Massage -> Qualifier = NULL;
Char = KeyConvert(Massage,NULL,NULL);
/* Just in case anybody needs it... */
Massage -> Qualifier = Qualifier;
ReplyMsg((struct Message *)Massage);
if(IClass == IDCMP_IDCMPUPDATE)
{
switch(GetTagData(GA_ID,0,TagList))
{
case GAD_UP:
if(TopLine > 0)
{
TopLine--;
MarkArea(-1,-1,-1);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
DisplayedLines = RedrawScreen(TopLine);
}
break;
case GAD_DOWN:
if(TopLine + NumBufferLines < Lines)
{
TopLine++;
MarkArea(-1,-1,-1);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
DisplayedLines = RedrawScreen(TopLine);
}
break;
}
}
if(IClass == IDCMP_MOUSEMOVE || IClass == IDCMP_GADGETDOWN || IClass == IDCMP_GADGETUP)
{
LONG Position;
GetAttr(PGA_Top,Scroller,&Position);
if(Position != TopLine)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(TopLine = Position);
}
}
if(IClass == IDCMP_RAWKEY)
{
if(Code == HELP_CODE)
GuideDisplay(CONTEXT_TEXTBUFFER);
if(LastChar)
{
if((Code & IECODE_UP_PREFIX) || !(LastQualifier & IEQUALIFIER_REPEAT))
{
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
}
if(LastChar = Char)
{
/* Use the numeric keypad keys to
* move through the buffer.
*/
if(Qualifier & IEQUALIFIER_NUMERICPAD)
{
/* Remove the numpad qualifier. */
Qualifier &= ~IEQUALIFIER_NUMERICPAD;
switch(Char - '0')
{
/* Jump to bottom. */
case 1: Char = CDN;
Qualifier |= IEQUALIFIER_CONTROL;
break;
/* Jump to top. */
case 7: Char = CUP;
Qualifier |= IEQUALIFIER_CONTROL;
break;
/* Move one page down. */
case 3: Char = CDN;
Qualifier |= IEQUALIFIER_LSHIFT;
break;
/* Move one page up. */
case 9: Char = CUP;
Qualifier |= IEQUALIFIER_LSHIFT;
break;
/* Move one line down. */
case 2: Char = CDN;
break;
/* Move one line up. */
case 8: Char = CUP;
break;
}
}
/* Check cursor keys. */
switch(Char)
{
/* Scroll the buffer up. */
case CUP:
if(Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
{
MarkArea(-1,-1,-1);
if(TopLine)
{
DisplayedLines = RedrawScreen(TopLine = 0);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
break;
}
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
LONG NewCurrentLine;
if((NewCurrentLine = TopLine - NumBufferLines) < 0)
NewCurrentLine = 0;
MarkArea(-1,-1,-1);
if(NewCurrentLine != TopLine)
{
DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
break;
}
if(TopLine)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(--TopLine);
}
break;
/* Scroll the buffer down. */
case CDN:
if(Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
{
LONG NewCurrentLine;
if((NewCurrentLine = Lines - NumBufferLines) < 0)
NewCurrentLine = 0;
MarkArea(-1,-1,-1);
if(TopLine != NewCurrentLine)
{
DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
break;
}
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
LONG NewCurrentLine;
if((NewCurrentLine = TopLine + (2 * NumBufferLines)) > Lines)
NewCurrentLine = Lines;
if((NewCurrentLine = NewCurrentLine - NumBufferLines) < 0)
NewCurrentLine = 0;
MarkArea(-1,-1,-1);
if(NewCurrentLine != TopLine)
{
DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,TopLine,
TAG_DONE);
}
break;
}
if(TopLine + NumBufferLines < Lines)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(++TopLine);
}
break;
}
LastQualifier = Qualifier;
}
else
LastQualifier = NULL;
continue;
}
/* User hit a mouse button. */
if(IClass == IDCMP_MOUSEBUTTONS && !(Code & IECODE_UP_PREFIX))
{
MarkArea(-1,-1,-1);
/* Reasonable dimensions? */
if(MouseY / LocalTextFontHeight < DisplayedLines && MouseX / LocalTextFontWidth < NumBufferColumns)
{
ObtainSemaphore(BufferSemaphore);
BufferClip();
LastTopLine = TopLine;
ReleaseSemaphore(BufferSemaphore);
if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
Signal(ThisProcess,SIG_CLIP);
break;
}
}
if(IClass == IDCMP_MENUPICK)
{
struct MenuItem *MenuItem;
while(Code != MENUNULL)
{
MenuItem = ItemAddress(BufferMenuStrip,Code);
switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
{
case MEN_SEARCH:
StartBufferSearch(TRUE);
break;
case MEN_REPEAT:
StartBufferSearch(FALSE);
break;
case MEN_GOTO:
if(Window)
BumpWindow(Window);
break;
case MEN_QUITBUF:
BufferTerminated = TRUE;
break;
case MEN_CLEARBUF_CONTENTS:
if(Lines)
{
BlockWindows();
BlockWindow(BufferWindow);
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
FreeBuffer();
ReleaseWindow(BufferWindow);
ReleaseWindows();
FlushMsg(BufferWindow);
TopLine = 0;
goto Restart;
}
else
{
if(MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
{
FreeBuffer();
ReleaseWindow(BufferWindow);
ReleaseWindows();
FlushMsg(BufferWindow);
TopLine = 0;
goto Restart;
}
}
ReleaseWindow(BufferWindow);
ReleaseWindows();
FlushMsg(BufferWindow);
}
break;
}
Code = MenuItem -> NextSelect;
}
}
}
}
while(!BufferTerminated);
RemoveGList(BufferWindow,Scroller,(UWORD)-1);
DeleteScroller();
}
FreeVec(BufferLineWidths);
}
if(Window)
BumpWindow(Window);
MarkArea(-1,-1,-1);
ScreenToBack(BufferScreen);
BufferWindow -> Flags |= WFLG_RMBTRAP;
ClearMenuStrip(BufferWindow);
CloseWindow(BufferWindow);
}
}
FreeMenus(BufferMenuStrip);
}
FreeVisualInfo(BufferVisualInfo);
}
CloseScreen(BufferScreen);
}
}
CloseFont(LocalFont);
}
}
/* Release the search buffer data. */
if(BufferSearchInfo)
{
DeleteSearchInfo(BufferSearchInfo);
BufferSearchInfo = NULL;
}
Forbid();
BufferProcess = NULL;
if(StartupMessage)
ReplyMsg(StartupMessage);
else
Signal(ThisProcess,SIG_HANDSHAKE);
}